package notify

import (
	"context"
	"encoding/json"
	"errors"
	"time"

	"open/pkg/bytedance"

	"gorm.io/gorm"

	v1 "open/api/open/notify/v1"
	"open/internal/model"
	"open/internal/model/event"
	"open/internal/model/field"
	"open/internal/types"
	"open/pkg/log"
)

// ModifyGuide 修改建议
type ModifyGuide struct {
	Name string `json:"name"` // 修改指引名
	Link string `json:"link"` // 修改指引链接
}

// AuditDetail 审核的具体细节，通过时为 null
type AuditDetail struct {
	Reason      string      `json:"reason"`      // 被拒原因
	ModifyGuide ModifyGuide `json:"modifyGuide"` //修改建议
	DetailFile  string      `json:"detailFile"`  // 审核拒绝描述附件，可能有可能没有
}

// AuditResult 各端的审核结果
type AuditResult struct {
	HostName    string        `json:"hostName"`    //宿主端英文简称
	Reason      []string      `json:"reason"`      // 如果被拒，被拒原因是 auditDetail 中所有拒绝原因的汇总
	Status      int           `json:"status"`      // 0或1，0代表不通过，1代表通过
	AuditDetail []AuditDetail `json:"auditDetail"` // 审核的具体细节，通过时为 null
}

// ModifyResult 修改app结果
type ModifyResult struct {
	Reason string `json:"reason"`
	Status int    `json:"status"` // 0或1，0代表不通过，1代表通过
	Advice int    `json:"advice"`
}

// Message Event message
type Message struct {
	Ticket                     string        `json:"Ticket"`
	FromUserName               string        `json:"FromUserName"`
	AppID                      string        `json:"AppId"`
	TpAppID                    string        `json:"TpAppId"`
	CreateTime                 string        `json:"CreateTime"`
	MsgType                    string        `json:"MsgType"`
	Event                      string        `json:"Event"`
	EventTime                  string        `json:"EventTime"`
	AuthorizationCode          string        `json:"AuthorizationCode"`
	AuthorizationCodeExpiresIn int           `json:"AuthorizationCodeExpiresIn"`
	AuditResults               []AuditResult `json:"AuditResults"`
	ModifyAppNameResults       ModifyResult  `json:"ModifyAppNameResults"`
	ModifyAppIntroResults      ModifyResult  `json:"ModifyAppIntroResults"`
	ModifyAppIconResults       ModifyResult  `json:"ModifyAppIconResults"`
}

// NotifyBytedance 字节跳动通知回调
func (s *Service) NotifyBytedance(ctx context.Context, req *v1.NotifyBytedanceRequest) (*v1.NotifyBytedanceReply, error) {
	err := s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var app *model.BytedanceOpenApp
		if app, err = s.dao.GetBytedanceOpenApp(ctx); err != nil {
			return
		}
		msg := bytedance.DecryptMsg(app.Key, req.Encrypt)
		now := time.Now()
		message := Message{}
		m, _ := json.Marshal(msg)
		_ = json.Unmarshal(m, &message)
		logger := log.FromContext(ctx)
		if message.AppID != "" {
			logger.Infof("接收到小程序(%v)事件, 消息内容: %s", message.AppID, m)
		}
		switch message.Event {
		case "PUSH":
			if message.MsgType == "Ticket" {
				app.Ticket = message.Ticket
				return s.dao.SaveByteDanceOpenApp(ctx, app)
			}
		case "AUTHORIZED":
			_, err := s.dao.LockBytedanceAuthApp(ctx, message.AppID)
			if err != nil {
				// 授权通知比前端调用先到
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return s.dao.CreateBytedanceSubApp(ctx, &model.BytedanceOpenSubApp{
						AppID:                      message.AppID,
						TpAppID:                    message.TpAppID,
						AuthorizationCode:          message.AuthorizationCode,
						AuthorizationCodeExpiresAt: now.Add(time.Second * time.Duration(message.AuthorizationCodeExpiresIn)),
						Status:                     types.BytedanceAuthorized,
					})
				}
				return err
			}
		case "UPDATE_AUTHORIZED":
			openSubApp, err := s.dao.LockBytedanceAuthApp(ctx, message.AppID)
			if err != nil {
				return err
			}
			openSubApp.Status = types.BytedanceAuthorized
			return s.dao.SaveBytedanceSubApp(ctx, openSubApp)
		case "UNAUTHORIZED":
			var subApp *model.BytedanceOpenSubApp
			if subApp, err = s.dao.LockBytedanceAuthApp(ctx, message.AppID); err != nil {
				return
			}
			subApp.Status = types.BytedanceAuthUnauthorized
			return s.dao.SaveBytedanceSubApp(ctx, subApp)
		case "PACKAGE_AUDIT":
			for _, r := range message.AuditResults {
				if r.HostName == "douyin" {
					var bytedanceMiniApp *model.BytedanceMiniApp
					bytedanceMiniApp, err = s.dao.GetBytedanceMiniApp(ctx, message.AppID)
					if err != nil {
						return
					}
					var appVersion *model.MiniAppVersion
					appVersion, err = s.dao.GetAppVersion(ctx, message.AppID, types.ByteDance)
					if err != nil {
						return
					}
					var appInfo *bytedance.AppInfo
					if appInfo, err = s.dao.GetBytedanceAppInfo(ctx, message.AppID); err != nil {
						return
					}
					bytedanceMiniApp.Name = appInfo.AppName
					bytedanceMiniApp.Icon = appInfo.AppIcon
					bytedanceMiniApp.Intro = appInfo.AppIntro
					if err = s.dao.SaveBytedanceMiniApp(ctx, bytedanceMiniApp); err != nil {
						return
					}
					appVersion.Stage = types.StageWaitRelease
					appVersion.Status = types.StatusAuditing
					if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
						return
					}
					schedule := &model.Schedule{
						RefID:     appVersion.ID,
						JobType:   types.TaskRelease,
						JobData:   field.JSON("{}"),
						JobStatus: types.ScheduleTaskInit,
					}
					if err = s.dao.CreateSchedule(ctx, schedule); err != nil {
						return
					}
					// 发送发布事件
					if err = s.dao.TxSend(ctx, event.TaskRelease{
						AppID:     message.AppID,
						Platform:  types.ByteDance,
						Timestamp: time.Now().Unix(),
					}); err != nil {
						return
					}
					break
				}
			}
		case "MODIFY_APP_INTRO":
			if message.ModifyAppIntroResults.Status == 1 {
				var bytedanceMiniApp *model.BytedanceMiniApp
				bytedanceMiniApp, err = s.dao.GetBytedanceMiniApp(ctx, message.AppID)
				if err != nil {
					return err
				}
				var appInfo *bytedance.AppInfo
				if appInfo, err = s.dao.GetBytedanceAppInfo(ctx, message.AppID); err != nil {
					return
				}
				bytedanceMiniApp.Intro = appInfo.AppIntro
				return s.dao.SaveBytedanceMiniApp(ctx, bytedanceMiniApp)
			}
		case "MODIFY_APP_NAME":
			if message.ModifyAppNameResults.Status == 1 {
				var bytedanceMiniApp *model.BytedanceMiniApp
				bytedanceMiniApp, err = s.dao.GetBytedanceMiniApp(ctx, message.AppID)
				if err != nil {
					return err
				}
				var appInfo *bytedance.AppInfo
				if appInfo, err = s.dao.GetBytedanceAppInfo(ctx, message.AppID); err != nil {
					return
				}
				bytedanceMiniApp.Name = appInfo.AppName
				return s.dao.SaveBytedanceMiniApp(ctx, bytedanceMiniApp)
			}
		case "MODIFY_APP_ICON":
			if message.ModifyAppIconResults.Status == 1 {
				var bytedanceMiniApp *model.BytedanceMiniApp
				bytedanceMiniApp, err = s.dao.GetBytedanceMiniApp(ctx, message.AppID)
				if err != nil {
					return err
				}
				var appInfo *bytedance.AppInfo
				if appInfo, err = s.dao.GetBytedanceAppInfo(ctx, message.AppID); err != nil {
					return
				}
				bytedanceMiniApp.Icon = appInfo.AppIcon
				return s.dao.SaveBytedanceMiniApp(ctx, bytedanceMiniApp)
			}
		default:
			logger.Infof("未知的消息类型:%v", message.Event)
		}

		return
	})
	return &v1.NotifyBytedanceReply{Message: "ok"}, err
}
